package com.wyh.yuhcloud.service.impl;

import com.qcloud.cos.COS;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.model.*;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.Upload;
import com.wyh.yuhcloud.dao.FileMapper;
import com.wyh.yuhcloud.dto.PageDto;
import com.wyh.yuhcloud.dto.QueryInfoDto;
import com.wyh.yuhcloud.entity.File;
import com.wyh.yuhcloud.entity.PageBean;
import com.wyh.yuhcloud.service.FileService;
import com.wyh.yuhcloud.util.DiyIDUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author wyh
 * @version 1.0
 * @date 2022/2/24 17:37
 */
@Service
public class FileServiceImpl implements FileService {

    private final Logger log = LoggerFactory.getLogger(FileServiceImpl.class);

    static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm ss");

    @Value("${spring.tengxun.accessKey}")
    private String accessKey;
    @Value("${spring.tengxun.secretKey}")
    private String secretKey;
    @Value("${spring.tengxun.bucket}")
    private String bucket;
    @Value("${spring.tengxun.bucketName}")
    private String bucketName;
    @Value("${spring.tengxun.path}")
    private String path;
    @Value("${spring.tengxun.qianzhui}")
    private String qianzhui;

    @Autowired
    private FileMapper fileMapper;


    @Override
    public PageBean<File> queryFile(PageDto pageDto) {
        int currentPage = pageDto.getCurrentPage();
        int rows = pageDto.getRows();
        String userId = pageDto.getUserId();
        List<File> files = fileMapper.queryByPage(currentPage, rows, userId);
        //获得总记录数
        int totalCount = fileMapper.totalCount(userId);
        //计算总页码
        int totalPage = (totalCount % pageDto.getRows()) == 0 ? totalCount / pageDto.getRows() : (totalCount / pageDto.getRows()) + 1;
        return initPageBean(files, totalCount, totalPage, currentPage, rows);
    }

    @Override
    public PageBean<File> queryMap(QueryInfoDto queryInfoDto) {
        int totalCount = fileMapper.queryTotalCount(queryInfoDto);
        //计算总页码
        int totalPage = (totalCount % queryInfoDto.getRows()) == 0 ? totalCount / queryInfoDto.getRows() : (totalCount / queryInfoDto.getRows()) + 1;
        //查询信息
        List<File> files = fileMapper.queryMap(queryInfoDto);
        log.info("id: " + queryInfoDto.getUserId() + "\t查询条件为:" + queryInfoDto.getQueryName() + "\t查询的信息为:" + files);
        return initPageBean(files, totalCount, totalPage, queryInfoDto.getCurrentPage(), queryInfoDto.getRows());
    }


    /**
     * 格式化pageBean对象
     *
     * @param files       信息
     * @param totalCount  总页数
     * @param totalPage   总页码
     * @param currentPage 当前页
     * @param rows        条数
     * @return
     */
    public PageBean<File> initPageBean(List<File> files, int totalCount, int totalPage, int currentPage, int rows) {
        PageBean<File> pageInfo = new PageBean<File>();
        pageInfo.setList(files);
        pageInfo.setCurrentPage(currentPage);
        pageInfo.setTotalCount(totalCount);
        pageInfo.setTotalPage(totalPage);
        pageInfo.setRows(rows);
        return pageInfo;
    }

    /**
     * 文件上传
     *
     * @param file
     * @param userId
     * @return
     */
    @Override
    public String uploadFile(MultipartFile file, String userId) {

        if (file.isEmpty()) {
            return null;
        }

        File upFile = new File();

        long time = System.currentTimeMillis();
        log.warn("上传开始时间:" + sdf.format(new Date()));
        String originalFilename = file.getOriginalFilename();//获得完整文件名
        String typeName = originalFilename.substring(originalFilename.lastIndexOf("."));//取后缀，文件类型
//        String newFileName = UUID.randomUUID() + typeName;//uuid拼接文件名
        String newFileName = originalFilename + new SimpleDateFormat("yyyy-MM-dd").format(new Date())+(time%100) + typeName;//uuid拼接文件名
        Calendar cal = Calendar.getInstance();//日历类
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH) + 1;
        int day = cal.get(Calendar.DATE) / 10;
        //获得cos客户端的多线程管理
        TransferManager transferManager = initTransferManager();
        // bucket的命名规则为{name}-{appid} ，此处填写的存储桶名称必须为此格式
        // 简单文件上传, 最大支持 5 GB, 此上传适用于小文件上传, 建议 20 M 以下的文件使用该接口
        // 大文件上传请参照 API 文档高级 API 上传
        java.io.File localFile = null;
        try {
            localFile = java.io.File.createTempFile("temp", null); //初始化文件格式,在存入短期文件夹前给其添加前缀和后缀
            file.transferTo(localFile); //上传的文件格式
            // 指定要上传到 COS 上的路径
            String key = "/" + this.qianzhui + "/" + year + "/" + month + "/" + day + "/" + newFileName;//创建当前日期文件,用于存储今日上传文件

            PutObjectRequest putObjectRequest = new PutObjectRequest(this.bucketName, key, localFile); //封装上传请求
            //PutObjectResult putObjectResult = cosclient.putObject(putObjectRequest);    //cos客户端发送请求
            // 本地文件上传
            Upload upload = transferManager.upload(putObjectRequest);
            // 异步（如果想等待传输结束，则调用 waitForUploadResult）
            //UploadResult uploadResult = upload.waitForUploadResult();
            //同步的等待上传结束waitForCompletion
            upload.waitForCompletion();
            log.info("上传结束时间:" + sdf.format(new Date()));
            log.warn("{}上传{}花费时间(ms):{}", userId, originalFilename, (System.currentTimeMillis() - time));
            String url = this.path + putObjectRequest.getKey();
            upFile.setUserId(userId);
            upFile.setFileId(new DiyIDUtils("WJ", 1).nextId(String.valueOf(System.currentTimeMillis() - time)));
            upFile.setFileName(originalFilename);
            upFile.setFileUrl(url);
            addFile(upFile);
            return url;
        } catch (IOException | InterruptedException e) {
            return null;
        } finally {
            // 关闭客户端(关闭后台线程)
            transferManager.shutdownNow();
        }

        //大型文件上传
     /*   long contentLength = file.length();
        long partSize = 5 * 1024 * 1024; // 设置每个分片大小为5MB.

        try {
            // 创建对象的Etag列表，并取回每个分片的Etag。
            List<PartETag> partETags = new ArrayList<PartETag>();
            // 初始化分片上传
            InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucket_name, key);
            InitiateMultipartUploadResult initResponse = s3.initiateMultipartUpload(initRequest);

            // 上传分片
            long filePosition = 0;
            for (int i = 1; filePosition < contentLength; i++) {
                partSize = Math.min(partSize, (contentLength - filePosition));
                UploadPartRequest uploadRequest = new UploadPartRequest()
                        .withBucketName(bucket_name)
                        .withKey(key)
                        .withUploadId(initResponse.getUploadId())
                        .withPartNumber(i)
                        .withFileOffset(filePosition)
                        .withFile(file)
                        .withPartSize(partSize);
                // 上传分片并将返回的Etag加入列表中
                UploadPartResult uploadResult = s3.uploadPart(uploadRequest);
                partETags.add(uploadResult.getPartETag());
                filePosition += partSize;
            }

            // 完成分片上传
            CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(bucket_name, key,
                    initResponse.getUploadId(), partETags);
            s3.completeMultipartUpload(compRequest);
        } catch (AmazonServiceException e) {
            e.printStackTrace();
        } catch (SdkClientException e) {
            e.printStackTrace();
        }*/
    }

    @Override
    public String addFile(File upFile) {
        try {
            fileMapper.AddFile(upFile);
            return "success";
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "error";
    }

    @Override
    public String delFile(String fileId, String userId) {

        if (fileId != null) {
            //从对象存储桶中删除
            String fileUrl = fileMapper.selectFile(fileId);
            String fileName = fileMapper.selectFileName(fileId);
            String key = fileUrl.replaceAll(path, "");

            try {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        TransferManager transferManager = null;
                        try {
                            //  生成cos客户端
                            transferManager = initTransferManager();
                            COS cosClient = transferManager.getCOSClient();
                            cosClient.deleteObject(bucketName, key);//删除桶中对应的文件
                            log.warn("id为{}\t删除成功{}", userId, fileName);

                        } catch (CosClientException e) {
                            e.printStackTrace();
                            log.warn("id为{}\t删除失败{}", userId, fileName);
                        } finally {
                            assert transferManager != null;
                            transferManager.shutdownNow(); //释放资源
                        }
                    }
                }).start();
                fileMapper.delFile(fileId);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return "success";
        }

        return "error";
    }

    @Override
    public Integer fileTotal(String userId) {
        return fileMapper.totalCount(userId);
    }


    /**
     * 初始化cos客户端
     *
     * @return TransferManager
     */
    public TransferManager initTransferManager() {
        // 1 初始化用户身份信息(secretId, secretKey) ,使用秘钥初始化
        COSCredentials cred = new BasicCOSCredentials(this.accessKey, this.secretKey);
        // 2 设置bucket的区域, COS地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
        ClientConfig clientConfig = new ClientConfig(new Region(this.bucket));
        // 3 生成cos客户端
        COSClient cosClient = new COSClient(cred, clientConfig);
        // 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
        ExecutorService threadPool = Executors.newFixedThreadPool(32);
        return new TransferManager(cosClient, threadPool);
    }
}
